# Copyright (c) 2018 Presto Labs Pte. Ltd.
# Author: leon

import ujson as json
import functools

from coin.base.book.types import TradeSide, create_market_trade_event
from coin.exchange.base.ws.handler import WebsocketHandler
from coin.exchange.fcoin.book_builder import BookBuilder
from coin.exchange.fcoin.kr_rest.product import FcoinProduct


@functools.lru_cache(maxsize=32)
def get_product_from_type_name(type):
  exploded = type.split('.')
  if len(exploded) == 3:
    # Depth case.
    event_type, _, symbol = type.split('.')
    assert event_type == 'depth'
    return FcoinProduct.FromStrNativeProduct(symbol)
  elif len(exploded) == 2:
    # Trade case.
    event_type, symbol = type.split('.')
    assert event_type == 'trade'
    return FcoinProduct.FromStrNativeProduct(symbol)
  else:
    raise ValueError(type)


class FcoinHandler(WebsocketHandler):
  def on_ws_depth(self, record, queue_data, topic_data):
    data = record.data
    if not isinstance(data, dict):
      data = json.loads(data.tobytes())

    assert 'type' in data
    type = data['type']
    product = get_product_from_type_name(type)
    native_symbol = product.native_symbol
    if not self.is_subscribed('book', native_symbol):
      return

    self._books.setdefault(native_symbol, BookBuilder(native_symbol))
    book = self._books[native_symbol]
    bids = data['bids']
    asks = data['asks']
    book.snapshot(bids, asks)
    book.update_timestamp(record.timestamp)
    self.ready = True

    if self._feed_checker:
      self._feed_checker.on_book(product=product, book=book, timestamp=record.timestamp)
    self.publish_event('book', book.symbol, book)

  def on_ws_trade(self, record, queue_data, topic_data):
    data = record.data
    if not isinstance(data, dict):
      data = json.loads(data.tobytes())

    assert 'type' in data
    type = data['type']
    product = get_product_from_type_name(type)
    native_symbol = product.native_symbol
    if not self.is_subscribed('trade', native_symbol):
      return

    price = data['price']
    qty = data['amount']
    if data['side'] == 'buy':
      side = TradeSide.TRADE_BUY_SIDE
    elif data['side'] == 'sell':
      side = TradeSide.TRADE_SELL_SIDE
    else:
      raise ValueError('Unknown side: %s', data)
    trade_event = create_market_trade_event(record.timestamp, native_symbol, price, qty, side)
    if self._feed_checker:
      self._feed_checker.on_trade(product=product,
                                  trade_event=trade_event,
                                  timestamp=record.timestamp)
    self.publish_event('trade', native_symbol, trade_event)
